#include <math.h>
#include <iostream>
#include <unordered_set>

using std::cout;
using std::endl;
using std::unordered_multiset;

template <typename Container>
void display(const Container &con)
{
    for(auto &elem : con)
    {
        cout << elem << "  ";
    }
    cout << endl;
}

class Point
{
public:
    Point(int ix = 0, int iy = 0)
    : _ix(ix)
    , _iy(iy)
    {
    }

    double getDistance() const
    {
        return hypot(_ix, _iy);
    }

    int getX() const
    {
        return _ix;
    }

    int getY() const
    {
        return _iy;
    }

    ~Point()
    {
    }

    friend std::ostream &operator<<(std::ostream &os, const Point &rhs);
private:
    int _ix;
    int _iy;
};

std::ostream &operator<<(std::ostream &os, const Point &rhs)
{
    os << "(" << rhs._ix
       << ", " << rhs._iy
       << ")";

    return os;
}

/*
    template<
        class key,
        class Hash = std::hash<key>,
        class KeyEqual = std::equal_to<Key>
     > class unordered_multiset;

*/

//命名空间的扩展
namespace std
{
//1、模板的特化
//在命名空间中对默认使用的哈希器进行扩展
//因为hash类在std中，现在将其特化针对Point
//相当于默认使用的std::hash里，有针对Point进行哈希计算的方法了
template <>
struct hash<Point>
{
    size_t operator()(const Point &rhs) const
    {
        cout<<"template<> struct hash"<<endl;
        return ( (rhs.getX() << 2) ^ (rhs.getY()<<1) );
    }
};//end of struct hash

//equal_to<key>姑且称为比较器
//那么也可以对它进行模板的特化
template <>
struct equal_to<Point>
{
    bool operator()(const Point &lhs, const Point &rhs) const
    {
        cout<<"template<> struct equal_to"<<endl;
        return ((lhs.getX() == rhs.getX()) && (lhs.getY() == rhs.getY()));
    }
};//end of struct equal_to

}//end of namespace std

//2、重载比较符
//默认的用于比较equal_to，里面的 == 没有针对Point类型
//如果没有在命名空间里对它的operator()函数进行重载，使其能够比较两个Point
//那么也可以对 == 进行重载
bool operator==(const Point &lhs, const Point &rhs)
{
    cout<<"bool operator==(const Point, const Point &)"<<endl;
    return ((lhs.getX() == rhs.getX()) && (lhs.getY() == rhs.getY()));
}

//3、自己写一个哈希器
//也叫函数对象
struct HashPoint
{
    size_t operator()(const Point &rhs) const
    {
        cout<<"struct HashPoint"<<endl;
        return ( (rhs.getX() << 2) ^ (rhs.getY()<<1) );
    }
};

//4、equal_to<key>姑且称为比较器
//自己写一个比较器
struct EqualToPoint
{
    bool operator()(const Point &lhs, const Point &rhs) const
    {
        cout<<"struct EqualToPoint"<<endl;
        return ((lhs.getX() == rhs.getX()) && (lhs.getY() == rhs.getY()));
    }
};

void test()
{
    //unordered_multiset<Point> number = { 
    unordered_multiset<Point, HashPoint, EqualToPoint> number = {
        Point(2, 2),
        Point(1, 2),
        Point(1, -2),
        Point(1, 2),
        Point(-1, 2),
        Point(3, 2),
    };
    display(number);
}

int main()
{
    test();
    return 0;
}


